home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / pasprog.EXE / SHOW_PCX.PAS < prev    next >
Pascal/Delphi Source File  |  1990-04-05  |  29KB  |  824 lines

  1. {$R-}    {Range checking off}
  2. {$B-}    {Boolean complete evaluation off}
  3. {$S-}    {Stack checking off}
  4. {$I+}    {I/O checking on}
  5. {$N-}    {No numeric coprocessor}
  6.  
  7. program show_pcx;
  8.  
  9. {****************************************************************************}
  10. {                                                                            }
  11. { SHOW_PCX is an example program written in Borland's Turbo Pascal(R) 5.0.   }
  12. { (Turbo Pascal is a registered trademark of Borland International, Inc.)    }
  13. { SHOW_PCX doesn't use any of the graphics routines built into Turbo Pascal, }
  14. { since many programmers won't be using Pascal for their final program.      }
  15. {                                                                            }
  16. {                            PERMISSION TO COPY:                             }
  17. {                                                                            }
  18. {          SHOW_PCX -- (C) Copyright 1989 ZSoft, Corporation.                }
  19. {                                                                            }
  20. { You are licensed to freely copy SHOW_PCX and incorporate it into your      }
  21. { own programs, provided that:                                               }
  22. {                                                                            }
  23. {  IF YOU COPY SHOW_PCX WITHOUT CHANGING IT:                                 }
  24. {  (1) You must retain this "Permission to Copy" notice, and                 }
  25. {  (2) You must not charge for the SHOW_PCX software or                      }
  26. {      documentation; however, you may charge a service fee for              }
  27. {      disk duplication and distribution, so long as such fee is             }
  28. {      not more than $5.00.                                                  }
  29. {                                                                            }
  30. {  IF YOU MODIFY SHOW_PCX AND/OR INCORPORATE SHOW_PCX INTO YOUR OWN PROGRAMS }
  31. {  (1) You must include the following acknowledgment notice in the           }
  32. {      appropriate places:                                                   }
  33. {                                                                            }
  34. {      Includes portions of SHOW_PCX.                                        }
  35. {      Used by permission of ZSoft Corporation.                              }
  36. {                                                                            }
  37. {                                                                            }
  38. { ZSoft Corporation reserves all rights to SHOW_PCX except as stated herein. }
  39. {                                                                            }
  40. {                                                                            }
  41. {                  [END OF "PERMISSION TO COPY" NOTICE]                      }
  42. {                                                                            }
  43. { This program reads a PC Paintbrush PCX file and shows it on the screen.    }
  44. { The picture must be a 2 color CGA, 4 color CGA, or a 16 color EGA picture. }
  45. { The picture will be displayed until a key is pressed.                      }
  46. {                                                                            }
  47. { This program can be run at the DOS prompt - 'SHOW_PCX SAMPLE.PCX'.         }
  48. {                                                                            }
  49. {****************************************************************************}
  50. {                                                                            }
  51. { Since this program is provided as a service, you are on your own when      }
  52. { when you modify it to work with your own programs.                         }
  53. {                                                                            }
  54. { We strive to make every program bug-free. If you find any bugs in this     }
  55. { program, please contact us on Compuserve (76702,1207)                      }
  56. { However, this program is provided AS IS and we are not responsible for any }
  57. { problems you might discover.                                               }
  58. {                                                                            }
  59. {****************************************************************************}
  60. {                                                                            }
  61. { Remember, some computers and video adapters are NOT 100% compatible, no    }
  62. { matter what their marketing department may say. This shows up when your    }
  63. { program runs on everyone's computer EXCEPT a particular clone.             }
  64. { Unfortunately, there is not much you can do to correct it.                 }
  65. {                                                                            }
  66. { For example, some early VGA cards do not support the BIOS calls to set up  }
  67. { a VGA palette - so the PCX image may come up all black, or with the wrong  }
  68. { colors.                                                                    }
  69. {                                                                            }
  70. { Also, if you use code that attempts to determine what kind of video card   }
  71. { is attached to the computer it may lock-up...                              }
  72. {                                                                            }
  73. {****************************************************************************}
  74. {                                                                            }
  75. { The PCX file format was originally developed in 1982, when there were only }
  76. { three video addapters: CGA, Hercules, and the Tecmar Graphics Master. Over }
  77. { the years, as new hardware became available (EGA, VGA, etc.), we had to    }
  78. { modify the format. Wherever posible, we insure downward compatiblity. This }
  79. { means, if you follow the suggestions in this program, your own program     }
  80. { should be able to read 'new' PCX files in the future.                      }
  81. {                                                                            }
  82. {****************************************************************************}
  83.  
  84. {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
  85. {
  86.   NEEDED ADDITIONS:
  87.   CGA palette - read old and new palette - set screen palette
  88. }
  89. {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
  90.  
  91.  
  92. uses
  93.   Crt, Dos;
  94.  
  95. const
  96.    MAX_WIDTH = 4000;    { arbitrary - maximum width (in bytes) of a PCX image }
  97.    COMPRESS_NUM = $C0;  { this is the upper two bits that indicate a count }
  98.    MAX_BLOCK = 4096;
  99.  
  100.    RED = 0;
  101.    GREEN = 1;
  102.    BLUE = 2;
  103.  
  104.    CGA4 = $04;          { video modes }
  105.    CGA2 = $06;
  106.    EGA  = $10;
  107.    VGA  = $12;
  108.    MCGA = $13;
  109.  
  110. type
  111.    str80 = string [80];
  112.    file_buffer = array [0..127] of byte;
  113.    block_array = array [0..MAX_BLOCK] of byte;
  114.    pal_array = array [0..255, RED..BLUE] of byte;
  115.    ega_array = array [0..16] of byte;
  116.    line_array = array [0..MAX_WIDTH] of byte;
  117.  
  118.    pcx_header = record
  119.         Manufacturer: byte;     { Always 10 for PCX file }
  120.  
  121.         Version: byte;          { 2 - old PCX - no palette (not used anymore),
  122.                                   3 - no palette,
  123.                                   4 - Microsoft Windows - no palette (only in
  124.                                       old files, new Windows version uses 3),
  125.                                   5 - with palette }
  126.  
  127.         Encoding: byte;         { 1 is PCX, it is possible that we may add
  128.                                   additional encoding methods in the future }
  129.  
  130.         Bits_per_pixel: byte;   { Number of bits to represent a pixel
  131.                                   (per plane) - 1, 2, 4, or 8 }
  132.  
  133.         Xmin: integer;          { Image window dimensions (inclusive) }
  134.         Ymin: integer;          { Xmin, Ymin are usually zero (not always) }
  135.         Xmax: integer;
  136.         Ymax: integer;
  137.  
  138.         Hdpi: integer;          { Resolution of image (dots per inch) }
  139.         Vdpi: integer;          { Set to scanner resolution - 300 is default }
  140.  
  141.         ColorMap: array [0..15, RED..BLUE] of byte;
  142.                                 { RGB palette data (16 colors or less)
  143.                                   256 color palette is appended to end of file }
  144.  
  145.         Reserved: byte;         { (used to contain video mode)
  146.                                   now it is ignored - just set to zero }
  147.  
  148.         Nplanes: byte;          { Number of planes }
  149.  
  150.         Bytes_per_line_per_plane: integer;   { Number of bytes to allocate
  151.                                                for a scanline plane.
  152.                                                MUST be an an EVEN number!
  153.                                                Do NOT calculate from Xmax-Xmin! }
  154.  
  155.         PaletteInfo: integer;   { 1 = black & white or color image,
  156.                                   2 = grayscale image - ignored in PB4, PB4+
  157.                                   palette must also be set to shades of gray! }
  158.  
  159.         HscreenSize: integer;   { added for PC Paintbrush IV Plus ver 1.0,  }
  160.         VscreenSize: integer;   { PC Paintbrush IV ver 1.02 (and later)     }
  161.                                 { I know it is tempting to use these fields
  162.                                   to determine what video mode should be used
  163.                                   to display the image - but it is NOT
  164.                                   recommended since the fields will probably
  165.                                   just contain garbage. It is better to have
  166.                                   the user install for the graphics mode he
  167.                                   wants to use... }
  168.  
  169.         Filler: array [74..127] of byte;     { Just set to zeros }
  170.         end;
  171.  
  172. var
  173.    Name: str80;                        { Name of PCX file to load }
  174.    ImageName: str80;                   { Name of PCX file - used by ReadError }
  175.    BlockFile: file;                    { file for reading block data }
  176.    BlockData: block_array;             { 4k data buffer }
  177.  
  178.    Header: pcx_header;                 { PCX file header }
  179.    Palette256: pal_array;              { place to put 256 color palette }
  180.    PaletteEGA: ega_array;              { place to put 17 EGA palette values }
  181.    PCXline: line_array;                { place to put uncompressed data }
  182.  
  183.    Ymax: integer;                      { maximum Y value on screen }
  184.    NextByte: integer;                  { index into file buffer in ReadByte }
  185.    Index: integer;                     { PCXline index - where to put Data }
  186.    Data: byte;                         { PCX compressed data byte }
  187.  
  188.    PictureMode: integer;               { Graphics mode number }
  189.    Reg: Registers;                     { Register set - used for int 10 calls }
  190.  
  191.  
  192. { ================================= Error ================================== }
  193.  
  194. procedure Error (s: str80 );
  195.  
  196. { Print out the error message and wait, then halt }
  197.  
  198. var c: char;
  199.     i: integer;
  200.  
  201. begin
  202. TextMode (C80);
  203. writeln ('ERROR');
  204. writeln (s);
  205. halt;
  206. end;   { Error }
  207.  
  208.  
  209. { =============================== ReadError =============================== }
  210.  
  211. procedure ReadError (msg: integer);
  212.  
  213. { Check for an i/o error }
  214.  
  215. begin
  216. if IOresult <> 0 then
  217.    case msg of
  218.    1: Error ('Can''t open file - ' + ImageName);
  219.    2: Error ('Error closing file - ' + ImageName + ' - disk may be full');
  220.    3: Error ('Error reading file - ' + ImageName);
  221.  
  222.    else
  223.       Error ('Error doing file I/O - ' + ImageName);
  224.    end;   { case }
  225. end;   { ReadError }
  226.  
  227.  
  228. { =========================== VideoMode =============================== }
  229.  
  230. procedure VideoMode (n: integer);
  231.  
  232. { Do a BIOS call to set the video mode }
  233. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  234.  
  235. begin
  236. Reg.ah := $00;
  237. Reg.al := n;                         { mode number }
  238. intr ($10, Reg);                     { call interrupt }
  239. end;  { VideoMode }
  240.  
  241.  
  242. { =========================== EGApalette =============================== }
  243.  
  244. procedure EGApalette (n, R, G, B: integer);
  245.  
  246. { Set a single EGA's palette register.
  247.   n is the index of the palette register.
  248.   R, G, and B are 0..255. }
  249.  
  250. { This code is never called - it is here as an example }
  251.  
  252. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  253.  
  254. var i: integer;
  255.  
  256. begin
  257. R := R shr 6;                        { R, G, and B are now 0..3 }
  258. G := G shr 6;
  259. B := B shr 6;
  260. i := (R shl 4) + (G shl 2) + B;
  261.  
  262. Reg.ah := $10;
  263. Reg.al := 0;                         { set individual palette register }
  264. Reg.bh := i;                         { value }
  265. Reg.bl := n;                         { palette register number }
  266. intr ($10, Reg);                     { call interrupt }
  267. end;  { EGApalette }
  268.  
  269.  
  270. { =========================== VGApalette =============================== }
  271.  
  272. procedure VGApalette (n, R, G, B: integer);
  273.  
  274. { Set a single VGA palette and DAC register pair.
  275.   n is the index of the palette register.
  276.   R, G, and B are 0..255. }
  277.  
  278. { This code is never called - it is here as an example }
  279.  
  280. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  281.  
  282. begin
  283. R := R shr 2;                        { R, G, and B are now 0..63 }
  284. G := G shr 2;
  285. B := B shr 2;
  286.  
  287. Reg.ah := $10;                       { Set Palette Call }
  288. Reg.al := $0;                        { set individual palette register }
  289. Reg.bl := n;                         { palette register number 0..15, 0..255 }
  290. Reg.bh := n;                         { palette register value }
  291. intr ($10, Reg);                     { call interrupt }
  292.  
  293. Reg.ah := $10;                       { Set DAC Call }
  294. Reg.al := $10;                       { set individual DAC register }
  295. Reg.bx := n;                         { DAC register number 0..15, 0..255 }
  296. Reg.dh := R;                         { red value 0..63 }
  297. Reg.ch := G;                         { green value 0..63 }
  298. Reg.cl := B;                         { blue value 0..63 }
  299. intr ($10, Reg);                     { call interrupt }
  300. end;  { VGApalette }
  301.  
  302.  
  303. { =========================== EGA16palette =============================== }
  304.  
  305. procedure EGA16palette;
  306.  
  307. { Set the EGA's entire 16 color palette. }
  308. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  309.  
  310. var
  311.    i, r, g, b: integer;
  312.  
  313. begin
  314. for i := 0 to 15 do
  315.    begin
  316.    r := Header.ColorMap [i, RED]   shr 6;       { r, g, and b are now 0..3 }
  317.    g := Header.ColorMap [i, GREEN] shr 6;
  318.    b := Header.ColorMap [i, BLUE]  shr 6;
  319.    PaletteEGA [i] := (r shl 4) + (g shl 2) + b;
  320.    end;
  321. PaletteEGA [16] := 0;                { border color }
  322.  
  323. Reg.ah := $10;                       { Set Palette Call }
  324. Reg.al := $02;                       { set a block of palette registers }
  325. Reg.dx := ofs (PaletteEGA);          { offset of block }
  326. Reg.es := seg (PaletteEGA);          { segment of block }
  327. intr ($10, Reg);                     { call interrupt }
  328.  
  329. end;  { EGA16palette }
  330.  
  331.  
  332. { =========================== VGA16palette =============================== }
  333.  
  334. procedure VGA16palette;
  335.  
  336. { Set the VGA's entire 16 color palette. }
  337. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  338.  
  339. var
  340.    i: integer;
  341.  
  342. begin
  343. for i := 0 to 15 do
  344.    PaletteEGA [i] := i;
  345. PaletteEGA [16] := 0;                { border color }
  346.  
  347. Reg.ah := $10;                       { Set Palette Call }
  348. Reg.al := $02;                       { set a block of palette registers }
  349. Reg.dx := ofs (PaletteEGA);          { offset of block }
  350. Reg.es := seg (PaletteEGA);          { segment of block }
  351. intr ($10, Reg);                     { call interrupt }
  352.  
  353. for i := 0 to 15 do
  354.    begin                                          { R, G, and B must be 0..63 }
  355.    Palette256 [i, RED]   := Header.ColorMap [i, RED]   shr 2;
  356.    Palette256 [i, GREEN] := Header.ColorMap [i, GREEN] shr 2;
  357.    Palette256 [i, BLUE]  := Header.ColorMap [i, BLUE]  shr 2;
  358.    end;
  359.  
  360. Reg.ah := $10;                       { Set DAC Call }
  361. Reg.al := $12;                       { set a block of DAC registers }
  362. Reg.bx := 0;                         { first DAC register number }
  363. Reg.cx := 255;                       { number of registers to update }
  364. Reg.dx := ofs (Palette256);          { offset of block }
  365. Reg.es := seg (Palette256);          { segment of block }
  366. intr ($10, Reg);                     { call interrupt }
  367.  
  368. end;  { VGA16palette }
  369.  
  370.  
  371. { =========================== EntireVGApalette =============================== }
  372.  
  373. procedure EntireVGApalette;
  374.  
  375. { Set the VGA's entire 256 color palette. }
  376. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  377.  
  378. var
  379.    i: integer;
  380.  
  381. begin
  382. for i := 0 to 255 do
  383.    begin                                          { R, G, and B must be 0..63 }
  384.    Palette256 [i, RED]   := Palette256 [i, RED]   shr 2;
  385.    Palette256 [i, GREEN] := Palette256 [i, GREEN] shr 2;
  386.    Palette256 [i, BLUE]  := Palette256 [i, BLUE]  shr 2;
  387.    end;
  388.  
  389. Reg.ah := $10;                       { Set DAC Call }
  390. Reg.al := $12;                       { set a block of DAC registers }
  391. Reg.bx := 0;                         { first DAC register number }
  392. Reg.cx := 255;                       { number of registers to update }
  393. Reg.dx := ofs (Palette256);          { offset of block }
  394. Reg.es := seg (Palette256);          { segment of block }
  395. intr ($10, Reg);                     { call interrupt }
  396.  
  397. end;  { EntireVGApalette }
  398.  
  399.  
  400. { =========================== SetPalette =============================== }
  401.  
  402. procedure SetPalette;
  403.  
  404. { Set up the entire graphics palette }
  405.  
  406. var i: integer;
  407.  
  408. begin
  409. if PictureMode = MCGA then
  410.    EntireVGApalette
  411. else if PictureMode = VGA then
  412.    VGA16palette
  413. else
  414.    EGA16palette;
  415. end;  { SetPalette }
  416.  
  417.  
  418. { =========================== ShowCGA =============================== }
  419.  
  420. procedure ShowCGA (Y: integer);
  421.  
  422. { Put a line of CGA data on the screen }
  423. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  424.  
  425. var
  426.    i, j, l, m, t: integer;
  427.    Yoffset: integer;
  428.    CGAScreen: array [0..32000] of byte absolute $B800:$0000;
  429.  
  430. begin
  431. i := 8 div Header.Bits_per_pixel;        { i is pixels per byte }
  432.  
  433. if (i = 8) then                          { 1 bit per pixel }
  434.    j := 7
  435. else                                     { 2 bits per pixel }
  436.    j := 3;
  437.  
  438. t := (Header.Xmax - Header.Xmin + 1);    { width in pixels }
  439. m := t and j;                            { left over bits }
  440.  
  441. l := (t + j) div i;                      { compute number of bytes to display }
  442. if l > 80 then
  443.    begin
  444.    l := 80;                              { don't overrun screen width }
  445.    m := 0;
  446.    end;
  447.  
  448. if (m <> 0) then                         { we need to mask unseen pixels }
  449.    begin
  450.    m := $FF shl (8 - (m * Header.Bits_per_pixel));   { m = mask }
  451.    t := l - 1;
  452.    PCXline [t] := PCXline [t] and m;     { mask off unseen pixels }
  453.    end;
  454.  
  455. Yoffset := 8192 * (Y and 1);
  456. Move (PCXline [0], CGAScreen [((Y shr 1) * 80) + Yoffset], l);
  457.  
  458. end;   { ShowCGA }
  459.  
  460.  
  461. { =========================== ShowEGA =============================== }
  462.  
  463. procedure ShowEGA (Y: integer);
  464.  
  465. { Put a line of EGA (or VGA) data on the screen }
  466. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  467.  
  468. var
  469.    i, j, l, m, t: integer;
  470.    EGAplane: integer;
  471.    EGAscreen: array [0..32000] of byte absolute $A000:$0000;
  472.  
  473. begin
  474. EGAplane := $0100;                       { the first plane to update }
  475. PortW [$3CE] := $0005;                   { use write mode 0 }
  476.  
  477. { PortW [$3CE] := $0005;      does port I/O by words. It is the same as:
  478.  
  479.   Out 03CEh,05h
  480.   Out 03CFh,00h
  481. }
  482.  
  483. t := (Header.Xmax - Header.Xmin + 1);    { width in pixels }
  484. m := t and 7;                            { left over bits }
  485.  
  486. l := (t + 7) shr 3;                      { compute number of bytes to display }
  487. if (l >= 80) then
  488.    begin
  489.    l := 80;                              { don't overrun screen width }
  490.    m := 0;
  491.    end;
  492.  
  493. if (m <> 0) then
  494.    m := $FF shl (8 - m)                  { m = mask for unseen pixels }
  495. else
  496.    m := $FF;
  497.  
  498. for i := 0 to Header.Nplanes-1 do
  499.    begin
  500.    j := i * Header.Bytes_per_line_per_plane;
  501.    t := j + l - 1;
  502.    PCXline [t] := PCXline [t] and m;           { mask off unseen pixels }
  503.  
  504.    PortW [$3C4] := EGAplane + 2;               { set plane number }
  505.    Move (PCXline [j], EGAscreen [Y * 80], l);
  506.    EGAplane := EGAplane shl 1;
  507.    end;
  508.  
  509. PortW [$3C4] := $0F02;                         { default plane mask }
  510. end;   { ShowEGA }
  511.  
  512.  
  513. { =========================== ShowMCGA =============================== }
  514.  
  515. procedure ShowMCGA (Y: integer);
  516.  
  517. { Put a line of MCGA data on the screen }
  518. { In Turbo Pascal, a '$' means the number is hexadeximal. }
  519.  
  520. var
  521.    l: integer;
  522.    MCGAscreen: array [0..64000] of byte absolute $A000:$0000;
  523.  
  524. begin
  525. l := Header.XMax - Header.Xmin;            { compute number of bytes to display }
  526. if l > 320 then
  527.    l := 320;                               { don't overrun screen width }
  528.  
  529. Move (PCXline [0], MCGAScreen [Y * 320], l);
  530.  
  531. end;   { ShowMCGA }
  532.  
  533.  
  534. { =========================== Read256palette =============================== }
  535.  
  536. procedure Read256palette;
  537.  
  538. { Read in a 256 color palette at end of PCX file }
  539.  
  540. var
  541.    i: integer;
  542.    b: byte;
  543.  
  544. begin
  545. seek (BlockFile, FileSize (BlockFile) - 769);
  546. BlockRead (BlockFile, b, 1);           { read indicator byte }
  547. ReadError (3);
  548.  
  549. if b <> 12 then                        { no palette here... }
  550.    exit;
  551.  
  552. BlockRead (BlockFile, Palette256, 3*256);
  553. ReadError (3);
  554.  
  555. seek (BlockFile, 128);                 { go back to start of PCX data }
  556.  
  557. end;  { Read256palette }
  558.  
  559.  
  560. { =========================== ReadHeader =============================== }
  561.  
  562. procedure ReadHeader;
  563.  
  564. { Load a picture header from a PC Paintbrush PCX file }
  565.  
  566. label WrongFormat;
  567.  
  568. begin
  569. {$I-}
  570. BlockRead (BlockFile, Header, 128);         { read 128 byte PCX header }
  571. ReadError (3);
  572.  
  573.                                             { Is it a PCX file? }
  574. if (Header.Manufacturer <> 10) or (Header.Encoding <> 1) then
  575.    begin
  576.    close (BlockFile);
  577.    Error ('This is not a valid PCX image file.');
  578.    end;
  579.  
  580. if (Header.Nplanes = 4) and (Header.Bits_per_pixel = 1) then
  581.    begin
  582.    if (Header.Ymax - Header.Ymin) <= 349 then
  583.       begin
  584.       PictureMode := EGA;
  585.       Ymax := 349;
  586.       end
  587.    else
  588.       begin
  589.       PictureMode := VGA;
  590.       Ymax := 479;
  591.       end;
  592.    end
  593. else if (Header.Nplanes = 1) then
  594.    begin
  595.    Ymax := 199;
  596.  
  597.    if (Header.Bits_per_pixel = 1) then
  598.       PictureMode := CGA2
  599.    else if (Header.Bits_per_pixel = 2) then
  600.       PictureMode := CGA4
  601.    else if (Header.Bits_per_pixel = 8) then
  602.       begin
  603.       PictureMode := MCGA;
  604.       if Header.Version = 5 then
  605.          Read256palette;
  606.       end
  607.    else
  608.       goto WrongFormat;
  609.    end
  610. else
  611.    begin
  612. WrongFormat:
  613.    close (BlockFile);
  614.    Error ('PCX file is in wrong format - It must be a CGA, EGA, VGA, or MCGA image');
  615.    end;
  616.  
  617. Index := 0;
  618. NextByte := MAX_BLOCK;          { indicates no data read in yet... }
  619.  
  620. end;  { ReadHeader }
  621.  
  622.  
  623. { =========================== ReadByte =============================== }
  624.  
  625. procedure ReadByte;
  626.  
  627. { read a single byte of data - use BlockRead because it is FAST! }
  628.  
  629. var
  630.    NumBlocksRead: integer;
  631.  
  632. begin
  633. if NextByte = MAX_BLOCK then
  634.    begin
  635.    BlockRead (BlockFile, BlockData, MAX_BLOCK, NumBlocksRead);
  636.    NextByte := 0;
  637.    end;
  638.  
  639. data := BlockData [NextByte];
  640. inc (NextByte);                         { NextByte++; }
  641. end;  { ReadByte }
  642.  
  643.  
  644. { =========================== Read_PCX_Line =============================== }
  645.  
  646. procedure Read_PCX_Line;
  647.  
  648. { Read a line from a PC Paintbrush PCX file }
  649.  
  650. var
  651.    count: integer;
  652.    bytes_per_line: integer;
  653.  
  654. begin
  655. {$I-}
  656.  
  657. bytes_per_line := Header.Bytes_per_line_per_plane * Header.Nplanes;
  658.  
  659.                           { bring in any data that wrapped from previous line }
  660.                           { usually none  -  this is just to be safe          }
  661. if Index <> 0 then
  662.    FillChar (PCXline [0], Index, data);    { fills a contiguous block of data }
  663.  
  664. while (Index < bytes_per_line) do          { read 1 line of data (all planes) }
  665.    begin
  666.    ReadByte;
  667.  
  668.    if (data and $C0) = compress_num then
  669.       begin
  670.       count := data and $3F;
  671.       ReadByte;
  672.       FillChar (PCXline [Index], count, data);  { fills a contiguous block }
  673.       inc (Index, count);                       { Index += count; }
  674.       end
  675.    else
  676.       begin
  677.       PCXline [Index] := data;
  678.       inc (Index);                              { Index++; }
  679.       end;
  680.    end;
  681.  
  682. ReadError (3);
  683.  
  684. Index := Index - bytes_per_line;
  685.  
  686. {$I+}
  687. end;  { Read_PCX_Line }
  688.  
  689.  
  690. { =========================== Read_PCX =============================== }
  691.  
  692. procedure Read_PCX (name: str80);
  693.  
  694. { Read PC Paintbrush PCX file and put it on the screen }
  695.  
  696. var
  697.    k, kmax: integer;
  698.  
  699. begin
  700. {$I-}
  701. ImageName := name;                     { used by ReadError }
  702.  
  703. assign (BlockFile, name);
  704. reset (BlockFile, 1);                  { use 1 byte blocks }
  705. ReadError (1);
  706.  
  707. ReadHeader;                            { read the PCX header }
  708.  
  709. { >>>>> No checking is done to see if the user has the correct hardware <<<<<
  710.   >>>>> to load the image. Your program sure verify the video mode is   <<<<<
  711.   >>>>> supported. Otherwise, the computer may lock-up.                 <<<<< }
  712.  
  713. VideoMode (PictureMode);               { switch to graphics mode }
  714. if Header.Version = 5 then
  715.    SetPalette;                         { set the screen palette, if available }
  716.  
  717. { >>>>> Note: You should compute the height of the image as follows. <<<<<
  718.   >>>>> Do NOT just read until End-Of-File!                          <<<<< }
  719.  
  720. kmax := Header.Ymin + Ymax;
  721. if Header.Ymax < kmax then        { don't show more than the screen can display }
  722.    kmax := Header.ymax;
  723.  
  724. if (PictureMode = EGA) or (PictureMode = VGA) then
  725.    begin
  726.    for k := Header.Ymin to kmax do          { each loop is separate for speed }
  727.       begin
  728.       Read_PCX_Line;
  729.       ShowEGA (k);
  730.       end;
  731.    end
  732. else if (PictureMode = MCGA) then
  733.    begin
  734.    for k := Header.Ymin to kmax do
  735.       begin
  736.       Read_PCX_Line;
  737.       ShowMCGA (k);
  738.       end;
  739.    end
  740. else                                         { it's a CGA picture }
  741.    begin
  742.    for k := Header.Ymin to kmax do
  743.       begin
  744.       Read_PCX_Line;
  745.       ShowCGA (k);
  746.       end;
  747.     end;
  748.  
  749. close (BlockFile);
  750. ReadError (2);
  751. {$I+}
  752. end;  { Read_PCX }
  753.  
  754.  
  755. { =========================== DISPLAY_PCX =============================== }
  756.  
  757. procedure display_pcx (name: str80);
  758.  
  759. { Display a PCX picture }
  760.  
  761. var
  762.    c: char;
  763.  
  764. begin
  765. Read_PCX (name);              { read and display the file }
  766.  
  767. while (not KeyPressed) do     { wait for any key to be pressed }
  768.    { nothing };
  769.  
  770. c := ReadKey;                 { now get rid of the key that was pressed }
  771. if c = #0 then                { handle function keys }
  772.    c := ReadKey;
  773.  
  774. end;   { display_pcx }
  775.  
  776.  
  777. { *************************** MAIN ******************************* }
  778.  
  779. begin
  780. ClrScr;
  781. writeln ('         SHOW_PCX - read and display a PC Paintbrush (R) picture');
  782. writeln;
  783. writeln ('                            PERMISSION TO COPY:');
  784. writeln ('            SHOW_PCX -- (C) Copyright 1989 ZSoft, Corporation.');
  785. writeln;
  786. writeln ('You are licensed to freely copy SHOW_PCX and incorporate it into your');
  787. writeln ('own programs, provided that:');
  788. writeln ('  IF YOU COPY SHOW_PCX WITHOUT CHANGING IT:');
  789. writeln ('  (1) You must retain this "Permission to Copy" notice, and');
  790. writeln ('  (2) You must not charge for the SHOW_PCX software or documentaion;');
  791. writeln ('      however, you may charge a service fee for disk duplication and');
  792. writeln ('      distribution, so long as such fee is not more than $5.00');
  793. writeln ('  IF YOU MODIFY SHOW_PCX AND/OR INCORPORATE SHOW_PCX INTO YOUR OWN PROGRAMS');
  794. writeln ('  (1) You must include the following notice in the appropriate places:');
  795. writeln ('      Includes portions of SHOW_PCX. Used by permission of ZSoft Corporation.');
  796. writeln;
  797. writeln (' ZSoft Corporation reserves all rights to SHOW_PCX except as stated herein.');
  798. writeln (' ZSoft Corporation,  450 Franklin Road, Suite 100,  Marietta, GA 30067');
  799. writeln (' (404) 428-0008');
  800. writeln ('                  [END OF "PERMISSION TO COPY" NOTICE]');
  801. writeln;
  802.  
  803. if (ParamCount = 0) then           { no DOS command line parameters }
  804.    begin
  805.    writeln ('The image must be a 2 or 4 color CGA, 16 color EGA or VGA,');
  806.    writeln ('or a 256 color MCGA picture');
  807.    writeln;
  808.  
  809.    write ('Enter name of picture file to display: ');
  810.    readln (name);
  811.    writeln;
  812.    end
  813. else
  814.    Name := ParamStr (1);           { get filename from DOS command line }
  815.  
  816. if (Pos ('.', Name) = 0) then      { make sure the filename has PCX extension }
  817.    Name := Concat (Name, '.pcx');
  818.  
  819. display_pcx (Name);
  820.  
  821. TextMode (co80);                   { back to text mode }
  822.  
  823. end.  { Show_PCX }
  824.